/*
 *  DDSDrawToImage.c
 *  DDSQuickLook
 *
 *  Created by Torsten Kammer on 16.02.08.
 *  Copyright 2008 __MyCompanyName__. All rights reserved.
 *
 */

#include "DDSDrawToImage.h"
#include <OpenGL/OpenGL.h>
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>

GLenum _dds_get_compressed_texture_format(const DDSFile *file)
{
	enum DDSDataFormat format = DDSGetDataFormat(file);
	switch(format)
	{
		case DDS_DXT1:
			return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
		case DDS_DXT3:
			return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
		case DDS_DXT5:
			return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
		
		default:
			return 0;
	}
}

void _dds_get_texture_format(const DDSFile *file, GLenum *format, GLenum *type)
{
	enum DDSDataFormat fileFormat = DDSGetDataFormat(file);
	*format = 0;
	*type = 0;
	switch(fileFormat)
	{
		case DDS_RGB_8:
			*format = GL_RGB;
			*type = GL_UNSIGNED_BYTE;
		break;
		case DDS_RGB_565:
			*format = GL_RGB;
			*type = GL_UNSIGNED_SHORT_5_6_5;
		break;
		case DDS_ARGB_8:
			*format = GL_BGRA;
			*type = GL_UNSIGNED_INT_8_8_8_8_REV;
		break;
		case DDS_ARGB_4:
			*format = GL_BGRA;
			*type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
		break;
		case DDS_ARGB_1555:
			*format = GL_BGRA;
			*type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
		break;
	}
}

Boolean _dds_upload_texture_data(const DDSFile *file, CFIndex mipmapLevel)
{
	CFIndex size;
	CFIndex width;
	CFIndex height;
	CFDataRef data;
	
	width = DDSGetWidth(file) >> mipmapLevel;
	height = DDSGetHeight(file) >> mipmapLevel;
	if (!width || !height) return 0;
	
	data = DDSGetDataForMipmapLevel(file, mipmapLevel);
	if (!data) return 0;
    const void *byteData = CFDataGetBytePtr(data);
    size = CFDataGetLength(data);
    
	if (DDSIsCompressed(file))
		glCompressedTexImage2D(GL_TEXTURE_2D, mipmapLevel, _dds_get_compressed_texture_format(file), width, height, 0, size, byteData);
	else
	{
		GLenum format;
		GLenum type;
		glTexImage2D(GL_TEXTURE_2D, mipmapLevel, GL_RGBA, width, height, 0, format, type, byteData);
	}
    
    CFRelease(data);
    
	return 1;
}

CGImageRef DDSCreateImage(const DDSFile *file, CFIndex maxWidth, CFIndex maxHeight)
{
	if (!file) return NULL;
	
	CGLPixelFormatObj pix;
	CGLPixelFormatAttribute attribs[] = { kCGLPFAColorSize, 24, kCGLPFAAlphaSize, 8, kCGLPFAOffScreen, 0 };
	GLint npix;
	CGLError result;
	
	result = CGLChoosePixelFormat(attribs, &pix, &npix);
	if (result != kCGLNoError) return 0;
	
	CGLContextObj ctx;
	result = CGLCreateContext(pix, NULL, &ctx);
	CGLDestroyPixelFormat(pix);
	if (result != kCGLNoError) return 0;
	
	char *offscreenBuffer = malloc(maxWidth * maxHeight * 4);
	result = CGLSetOffScreen(ctx, maxWidth, maxHeight, maxWidth * 4, offscreenBuffer);
	if (result != kCGLNoError)
	{
		free(offscreenBuffer);
		CGLDestroyContext(ctx);
		return 0;
	}
	CGLSetCurrentContext(ctx);
	
	glViewport(0, 0, maxWidth, maxHeight);
	gluOrtho2D(0.0, 0.0, 1.0, 1.0);
	
	glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT);
	
	glEnable(GL_TEXTURE_2D);
	
	glBindTexture(GL_TEXTURE_2D, 2);
	
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, DDSHasMipmaps(file) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
	
	glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
	
	CFIndex mipmap = 0;
	while (_dds_upload_texture_data(file, mipmap))
		mipmap++;
	
	glBegin(GL_QUADS);
	
	glTexCoord2f(0.0f, 0.0f);
	glVertex2f(-1.0f, -1.0f);
	
	glTexCoord2f(1.0f, 0.0f);
	glVertex2f(1.0f, -1.0f);
	
	glTexCoord2f(1.0f, 1.0f);
	glVertex2f(1.0f, 1.0f);
	
	glTexCoord2f(0.0f, 1.0f);
	glVertex2f(-1.0f, 1.0f);
	
	glEnd();
	
	CGLClearDrawable(ctx);
	CGLDestroyContext(ctx);
	
	// Copy data to CGImage
	
	CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
	CFDataRef data = CFDataCreate(kCFAllocatorDefault, (const void *) offscreenBuffer, maxWidth * maxHeight * 4);
	CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData(data);
	CFRelease(data);
    CGBitmapInfo flags = (CFByteOrderGetCurrent() == CFByteOrderLittleEndian) ? (kCGImageAlphaFirst | kCGBitmapByteOrder32Little) : (kCGImageAlphaFirst | kCGBitmapByteOrder32Big);
	CGImageRef image = CGImageCreate(maxWidth, maxHeight, 8, 32, maxWidth * 4, colorSpace, flags, dataProvider, NULL, true, kCGRenderingIntentDefault);
	CGColorSpaceRelease(colorSpace);
	CGDataProviderRelease(dataProvider);
	
	free(offscreenBuffer);
	
	return image;
}